import {
  IsString,
  IsOptional,
  IsEnum,
  IsBoolean,
  IsNumber,
  IsArray,
  MinLength,
  MaxLength,
  IsUUID,
  IsInt,
  Min,
  Max,
  ValidateNested,
  IsDateString,
  IsMimeType
} from 'class-validator'
import { Transform, Type } from 'class-transformer'
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'
import { PaginationDto } from './base.dto'
import { IsFileType } from '../validators/custom.validators'

/**
 * 文件类型枚举
 */
export enum FileType {
  IMAGE = 'image',
  VIDEO = 'video',
  AUDIO = 'audio',
  DOCUMENT = 'document',
  ARCHIVE = 'archive',
  OTHER = 'other'
}

/**
 * 文件状态枚举
 */
export enum FileStatus {
  UPLOADING = 'uploading',
  COMPLETED = 'completed',
  FAILED = 'failed',
  PROCESSING = 'processing',
  DELETED = 'deleted'
}

/**
 * 存储类型枚举
 */
export enum StorageType {
  LOCAL = 'local',
  OSS = 'oss',
  S3 = 's3',
  QINIU = 'qiniu',
  UPYUN = 'upyun'
}

/**
 * 文件上传DTO
 */
export class UploadFileDto {
  @ApiPropertyOptional({ description: '文件描述', example: '用户头像图片' })
  @IsOptional()
  @IsString({ message: '文件描述必须是字符串' })
  @MaxLength(500, { message: '文件描述不能超过500个字符' })
  @Transform(({ value }) => value?.trim())
  description?: string

  @ApiPropertyOptional({ description: '文件分类', example: 'avatar' })
  @IsOptional()
  @IsString({ message: '文件分类必须是字符串' })
  @MaxLength(50, { message: '文件分类不能超过50个字符' })
  @Transform(({ value }) => value?.toLowerCase().trim())
  category?: string

  @ApiPropertyOptional({ description: '是否公开访问', example: true })
  @IsOptional()
  @IsBoolean({ message: '是否公开访问必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  isPublic?: boolean = true

  @ApiPropertyOptional({ description: '关联实体类型', example: 'user' })
  @IsOptional()
  @IsString({ message: '关联实体类型必须是字符串' })
  @MaxLength(50, { message: '关联实体类型不能超过50个字符' })
  entityType?: string

  @ApiPropertyOptional({ description: '关联实体ID', example: 'uuid-123' })
  @IsOptional()
  @IsUUID('4', { message: '关联实体ID格式不正确' })
  entityId?: string

  @ApiPropertyOptional({ description: '存储类型', enum: StorageType, example: StorageType.LOCAL })
  @IsOptional()
  @IsEnum(StorageType, { message: '存储类型不正确' })
  storageType?: StorageType = StorageType.LOCAL

  @ApiPropertyOptional({ description: '是否压缩图片', example: true })
  @IsOptional()
  @IsBoolean({ message: '是否压缩图片必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  compress?: boolean = true

  @ApiPropertyOptional({ description: '图片质量（1-100）', example: 80 })
  @IsOptional()
  @IsInt({ message: '图片质量必须是整数' })
  @Min(1, { message: '图片质量不能小于1' })
  @Max(100, { message: '图片质量不能大于100' })
  @Transform(({ value }) => parseInt(value, 10))
  quality?: number = 80

  @ApiPropertyOptional({ description: '图片最大宽度', example: 1920 })
  @IsOptional()
  @IsInt({ message: '图片最大宽度必须是整数' })
  @Min(1, { message: '图片最大宽度不能小于1' })
  @Transform(({ value }) => parseInt(value, 10))
  maxWidth?: number

  @ApiPropertyOptional({ description: '图片最大高度', example: 1080 })
  @IsOptional()
  @IsInt({ message: '图片最大高度必须是整数' })
  @Min(1, { message: '图片最大高度不能小于1' })
  @Transform(({ value }) => parseInt(value, 10))
  maxHeight?: number
}

/**
 * 批量上传DTO
 */
export class BatchUploadDto extends UploadFileDto {
  @ApiProperty({ description: '文件数量', example: 5 })
  @IsInt({ message: '文件数量必须是整数' })
  @Min(1, { message: '文件数量不能小于1' })
  @Max(20, { message: '文件数量不能大于20' })
  @Transform(({ value }) => parseInt(value, 10))
  fileCount: number
}

/**
 * 更新文件DTO
 */
export class UpdateFileDto {
  @ApiPropertyOptional({ description: '文件名称', example: 'avatar.jpg' })
  @IsOptional()
  @IsString({ message: '文件名称必须是字符串' })
  @MinLength(1, { message: '文件名称不能为空' })
  @MaxLength(255, { message: '文件名称不能超过255个字符' })
  @Transform(({ value }) => value?.trim())
  filename?: string

  @ApiPropertyOptional({ description: '文件描述', example: '用户头像图片' })
  @IsOptional()
  @IsString({ message: '文件描述必须是字符串' })
  @MaxLength(500, { message: '文件描述不能超过500个字符' })
  @Transform(({ value }) => value?.trim())
  description?: string

  @ApiPropertyOptional({ description: '文件分类', example: 'avatar' })
  @IsOptional()
  @IsString({ message: '文件分类必须是字符串' })
  @MaxLength(50, { message: '文件分类不能超过50个字符' })
  @Transform(({ value }) => value?.toLowerCase().trim())
  category?: string

  @ApiPropertyOptional({ description: '是否公开访问', example: true })
  @IsOptional()
  @IsBoolean({ message: '是否公开访问必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  isPublic?: boolean

  @ApiPropertyOptional({ description: '关联实体类型', example: 'user' })
  @IsOptional()
  @IsString({ message: '关联实体类型必须是字符串' })
  @MaxLength(50, { message: '关联实体类型不能超过50个字符' })
  entityType?: string

  @ApiPropertyOptional({ description: '关联实体ID', example: 'uuid-123' })
  @IsOptional()
  @IsUUID('4', { message: '关联实体ID格式不正确' })
  entityId?: string

  @ApiPropertyOptional({ description: '文件标签', example: ['头像', '用户'] })
  @IsOptional()
  @IsArray({ message: '文件标签必须是数组' })
  @IsString({ each: true, message: '标签必须是字符串' })
  @MaxLength(20, { each: true, message: '标签长度不能超过20个字符' })
  tags?: string[]

  @ApiPropertyOptional({ description: 'Alt文本（图片）', example: '用户头像' })
  @IsOptional()
  @IsString({ message: 'Alt文本必须是字符串' })
  @MaxLength(200, { message: 'Alt文本不能超过200个字符' })
  @Transform(({ value }) => value?.trim())
  altText?: string
}

/**
 * 文件查询DTO
 */
export class QueryFileDto extends PaginationDto {
  @ApiPropertyOptional({ description: '搜索关键词（文件名、描述）', example: 'avatar' })
  @IsOptional()
  @IsString({ message: '搜索关键词必须是字符串' })
  @MaxLength(100, { message: '搜索关键词不能超过100个字符' })
  @Transform(({ value }) => value?.trim())
  search?: string = ''

  @ApiPropertyOptional({ description: '文件类型', enum: FileType, example: FileType.IMAGE })
  @IsOptional()
  @IsEnum(FileType, { message: '文件类型不正确' })
  type?: FileType

  @ApiPropertyOptional({ description: '文件状态', enum: FileStatus, example: FileStatus.COMPLETED })
  @IsOptional()
  @IsEnum(FileStatus, { message: '文件状态不正确' })
  status?: FileStatus

  @ApiPropertyOptional({ description: '文件分类', example: 'avatar' })
  @IsOptional()
  @IsString({ message: '文件分类必须是字符串' })
  @MaxLength(50, { message: '文件分类不能超过50个字符' })
  @Transform(({ value }) => value?.toLowerCase().trim())
  category?: string

  @ApiPropertyOptional({ description: '上传者ID', example: 'uuid-123' })
  @IsOptional()
  @IsUUID('4', { message: '上传者ID格式不正确' })
  uploaderId?: string

  @ApiPropertyOptional({ description: '关联实体类型', example: 'user' })
  @IsOptional()
  @IsString({ message: '关联实体类型必须是字符串' })
  @MaxLength(50, { message: '关联实体类型不能超过50个字符' })
  entityType?: string

  @ApiPropertyOptional({ description: '关联实体ID', example: 'uuid-123' })
  @IsOptional()
  @IsUUID('4', { message: '关联实体ID格式不正确' })
  entityId?: string

  @ApiPropertyOptional({ description: '存储类型', enum: StorageType, example: StorageType.LOCAL })
  @IsOptional()
  @IsEnum(StorageType, { message: '存储类型不正确' })
  storageType?: StorageType

  @ApiPropertyOptional({ description: '是否公开访问', example: true })
  @IsOptional()
  @IsBoolean({ message: '是否公开访问必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  isPublic?: boolean

  @ApiPropertyOptional({ description: '最小文件大小（字节）', example: 1024 })
  @IsOptional()
  @IsInt({ message: '最小文件大小必须是整数' })
  @Min(0, { message: '最小文件大小不能小于0' })
  @Transform(({ value }) => parseInt(value, 10))
  minSize?: number

  @ApiPropertyOptional({ description: '最大文件大小（字节）', example: 10485760 })
  @IsOptional()
  @IsInt({ message: '最大文件大小必须是整数' })
  @Min(0, { message: '最大文件大小不能小于0' })
  @Transform(({ value }) => parseInt(value, 10))
  maxSize?: number

  @ApiPropertyOptional({ description: 'MIME类型', example: 'image/jpeg' })
  @IsOptional()
  @IsMimeType({ message: 'MIME类型格式不正确' })
  mimeType?: string

  @ApiPropertyOptional({ description: '上传开始日期', example: '2024-01-01' })
  @IsOptional()
  @IsDateString({}, { message: '上传开始日期格式不正确' })
  uploadedFrom?: string

  @ApiPropertyOptional({ description: '上传结束日期', example: '2024-12-31' })
  @IsOptional()
  @IsDateString({}, { message: '上传结束日期格式不正确' })
  uploadedTo?: string

  @ApiPropertyOptional({ description: '文件标签', example: ['头像', '用户'] })
  @IsOptional()
  @IsArray({ message: '文件标签必须是数组' })
  @IsString({ each: true, message: '标签必须是字符串' })
  tags?: string[]
}

/**
 * 文件响应DTO
 */
export class FileResponseDto {
  @ApiProperty({ description: '文件ID', example: 'uuid-123' })
  id: string

  @ApiProperty({ description: '文件名称', example: 'avatar.jpg' })
  filename: string

  @ApiProperty({ description: '原始文件名', example: 'user_avatar_2024.jpg' })
  originalName: string

  @ApiProperty({ description: '文件路径', example: '/uploads/images/2024/01/avatar.jpg' })
  path: string

  @ApiProperty({
    description: '文件URL',
    example: 'https://example.com/uploads/images/2024/01/avatar.jpg'
  })
  url: string

  @ApiPropertyOptional({
    description: '缩略图URL',
    example: 'https://example.com/uploads/images/2024/01/avatar_thumb.jpg'
  })
  thumbnailUrl?: string

  @ApiProperty({ description: '文件大小（字节）', example: 1048576 })
  size: number

  @ApiProperty({ description: '文件大小（格式化）', example: '1.0 MB' })
  sizeFormatted: string

  @ApiProperty({ description: 'MIME类型', example: 'image/jpeg' })
  mimeType: string

  @ApiProperty({ description: '文件类型', enum: FileType, example: FileType.IMAGE })
  type: FileType

  @ApiProperty({ description: '文件状态', enum: FileStatus, example: FileStatus.COMPLETED })
  status: FileStatus

  @ApiPropertyOptional({ description: '文件描述', example: '用户头像图片' })
  description?: string

  @ApiPropertyOptional({ description: '文件分类', example: 'avatar' })
  category?: string

  @ApiProperty({ description: '是否公开访问', example: true })
  isPublic: boolean

  @ApiPropertyOptional({ description: '关联实体类型', example: 'user' })
  entityType?: string

  @ApiPropertyOptional({ description: '关联实体ID', example: 'uuid-123' })
  entityId?: string

  @ApiProperty({ description: '存储类型', enum: StorageType, example: StorageType.LOCAL })
  storageType: StorageType

  @ApiPropertyOptional({ description: '文件标签', example: ['头像', '用户'] })
  tags?: string[]

  @ApiPropertyOptional({ description: 'Alt文本（图片）', example: '用户头像' })
  altText?: string

  @ApiPropertyOptional({ description: '图片元数据' })
  metadata?: {
    width?: number
    height?: number
    format?: string
    colorSpace?: string
    hasAlpha?: boolean
    orientation?: number
    density?: number
  }

  @ApiPropertyOptional({ description: '视频元数据' })
  videoMetadata?: {
    duration?: number
    bitrate?: number
    fps?: number
    codec?: string
    resolution?: string
  }

  @ApiPropertyOptional({ description: '音频元数据' })
  audioMetadata?: {
    duration?: number
    bitrate?: number
    sampleRate?: number
    channels?: number
    codec?: string
  }

  @ApiProperty({ description: '下载次数', example: 25 })
  downloadCount: number

  @ApiProperty({ description: '访问次数', example: 150 })
  viewCount: number

  @ApiPropertyOptional({ description: '上传者信息' })
  uploader?: {
    id: string
    username: string
    realName?: string
  }

  @ApiPropertyOptional({ description: '最后访问时间', example: '2024-01-01T00:00:00.000Z' })
  lastAccessedAt?: Date

  @ApiProperty({ description: '上传时间', example: '2024-01-01T00:00:00.000Z' })
  uploadedAt: Date

  @ApiProperty({ description: '创建时间', example: '2024-01-01T00:00:00.000Z' })
  createdAt: Date

  @ApiProperty({ description: '更新时间', example: '2024-01-01T00:00:00.000Z' })
  updatedAt: Date
}

/**
 * 文件统计DTO
 */
export class FileStatsDto {
  @ApiProperty({ description: '总文件数', example: 1000 })
  total: number

  @ApiProperty({ description: '总文件大小（字节）', example: 1073741824 })
  totalSize: number

  @ApiProperty({ description: '总文件大小（格式化）', example: '1.0 GB' })
  totalSizeFormatted: string

  @ApiProperty({ description: '各类型文件数统计' })
  typeStats: Record<FileType, number>

  @ApiProperty({ description: '各状态文件数统计' })
  statusStats: Record<FileStatus, number>

  @ApiProperty({ description: '各存储类型文件数统计' })
  storageStats: Record<StorageType, number>

  @ApiProperty({ description: '今日上传文件数', example: 15 })
  todayUploads: number

  @ApiProperty({ description: '本月上传文件数', example: 200 })
  monthUploads: number

  @ApiProperty({ description: '热门文件（按下载次数）' })
  popularFiles: Array<{
    id: string
    filename: string
    url: string
    downloadCount: number
    type: FileType
  }>

  @ApiProperty({ description: '最新上传文件' })
  recentFiles: Array<{
    id: string
    filename: string
    url: string
    size: number
    type: FileType
    uploadedAt: Date
  }>

  @ApiProperty({ description: '大文件列表（>10MB）' })
  largeFiles: Array<{
    id: string
    filename: string
    size: number
    sizeFormatted: string
    type: FileType
  }>

  @ApiProperty({ description: '上传趋势（最近7天）' })
  uploadTrend: Array<{
    date: string
    count: number
    size: number
  }>

  @ApiProperty({ description: '存储使用情况' })
  storageUsage: {
    used: number
    usedFormatted: string
    available: number
    availableFormatted: string
    total: number
    totalFormatted: string
    percentage: number
  }
}

/**
 * 批量操作文件DTO
 */
export class BulkFileOperationDto {
  @ApiProperty({ description: '文件ID列表', example: ['uuid-1', 'uuid-2'] })
  @IsArray({ message: '文件ID列表必须是数组' })
  @IsUUID('4', { each: true, message: '文件ID格式不正确' })
  fileIds: string[]

  @ApiProperty({
    description: '操作类型',
    enum: ['delete', 'move', 'copy', 'changeCategory', 'changeVisibility']
  })
  @IsEnum(['delete', 'move', 'copy', 'changeCategory', 'changeVisibility'], {
    message: '操作类型不正确'
  })
  operation: 'delete' | 'move' | 'copy' | 'changeCategory' | 'changeVisibility'

  @ApiPropertyOptional({
    description: '目标分类（移动/复制/更改分类时使用）',
    example: 'documents'
  })
  @IsOptional()
  @IsString({ message: '目标分类必须是字符串' })
  @MaxLength(50, { message: '目标分类不能超过50个字符' })
  targetCategory?: string

  @ApiPropertyOptional({ description: '是否公开（更改可见性时使用）', example: true })
  @IsOptional()
  @IsBoolean({ message: '是否公开必须是布尔值' })
  @Transform(({ value }) => value === 'true' || value === true)
  isPublic?: boolean

  @ApiPropertyOptional({ description: '操作原因', example: '批量清理无用文件' })
  @IsOptional()
  @IsString({ message: '操作原因必须是字符串' })
  @MaxLength(500, { message: '操作原因不能超过500个字符' })
  reason?: string
}

/**
 * 文件压缩DTO
 */
export class CompressFileDto {
  @ApiProperty({ description: '图片质量（1-100）', example: 80 })
  @IsInt({ message: '图片质量必须是整数' })
  @Min(1, { message: '图片质量不能小于1' })
  @Max(100, { message: '图片质量不能大于100' })
  @Transform(({ value }) => parseInt(value, 10))
  quality: number

  @ApiPropertyOptional({ description: '最大宽度', example: 1920 })
  @IsOptional()
  @IsInt({ message: '最大宽度必须是整数' })
  @Min(1, { message: '最大宽度不能小于1' })
  @Transform(({ value }) => parseInt(value, 10))
  maxWidth?: number

  @ApiPropertyOptional({ description: '最大高度', example: 1080 })
  @IsOptional()
  @IsInt({ message: '最大高度必须是整数' })
  @Min(1, { message: '最大高度不能小于1' })
  @Transform(({ value }) => parseInt(value, 10))
  maxHeight?: number

  @ApiPropertyOptional({ description: '输出格式', enum: ['jpeg', 'png', 'webp'] })
  @IsOptional()
  @IsEnum(['jpeg', 'png', 'webp'], { message: '输出格式不正确' })
  format?: 'jpeg' | 'png' | 'webp'
}

/**
 * 文件转换DTO
 */
export class ConvertFileDto {
  @ApiProperty({ description: '目标格式', example: 'webp' })
  @IsString({ message: '目标格式必须是字符串' })
  @MaxLength(10, { message: '目标格式不能超过10个字符' })
  targetFormat: string

  @ApiPropertyOptional({ description: '转换选项（JSON格式）', example: '{"quality": 80}' })
  @IsOptional()
  @IsString({ message: '转换选项必须是字符串' })
  options?: string
}
